#图像色彩空间转换 cv.cvtColor（），cv.inRange（）
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

flags = [i for i in dir(cv) if i.startswith('COLOR_')]
print(flags)
#输出各种转换方法

#追踪蓝色
cap = cv.VideoCapture(0)
while True:
    ret , frame = cap.read()
    hsv = cv.cvtColor(frame,cv.COLOR_BGR2HSV)
    #蓝色的阈值
    lower_blue = np.array([110, 50, 50])
    upper_blue = np.array([130, 255, 255])
    mask = cv.inRange(hsv,lower_blue,upper_blue)
    res = cv.bitwise_and(frame,frame,mask = mask)
    cv.imshow('frame', frame)
    cv.imshow('hsv', hsv)
    cv.imshow('mask', mask)
    cv.imshow('res', res)
    k = cv.waitKey(5) & 0xFF
    if k == 27:
        break
cv.destroyAllWindows()

#要查找Green的HSV值
#以[H-10，100,100]和[H + 10，255，255]作为下限和上限
green = np.uint8([[[0,255,0]]])
hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)
print(hsv_green)  #[[[ 60 255 255]]]

#追踪蓝色和绿色
cap = cv.VideoCapture(0)
while True:
    ret , frame = cap.read()
    hsv = cv.cvtColor(frame,cv.COLOR_BGR2HSV)
    #蓝色的阈值
    lower_blue = np.array([110, 50, 50])
    upper_blue = np.array([130, 255, 255])
    #绿色的阈值
    lower_green = np.array([50, 50, 50])
    upper_green = np.array([70, 255, 255])
    mask1 = cv.inRange(hsv,lower_blue,upper_blue)
    mask2 = cv.inRange(hsv, lower_green, upper_green)
    res1 = cv.bitwise_and(frame,frame,mask = mask1)
    res2 = cv.bitwise_and(frame, frame, mask=mask2)
    res = cv.bitwise_or(res1, res2)
    #cv.imshow('frame', frame)
    #cv.imshow('hsv', hsv)
    #cv.imshow('mask1', mask1)
    #cv.imshow('mask2', mask2)
    cv.imshow('res', res)
    k = cv.waitKey(5) & 0xFF
    if k == 27:
        break
cv.destroyAllWindows()


#图像的几何变换
'''
平移，旋转，仿射变换
cv.warpAffine和cv.warpPerspective
cv.warpAffine采用2x3转换矩阵，而cv.warpPerspective采用3x3转换矩阵作为输入。
'''
#放大的方法，两种
img = cv.imread('1.png')
res = cv.resize(img,None,fx = 2,fy = 2,interpolation = cv.INTER_CUBIC)
cv.imshow('img',res)
cv.waitKey(0)
cv.destroyAllWindows()

#方法二
height, width = img.shape[:2]
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)
cv.imshow('img',res)
cv.waitKey(0)
cv.destroyAllWindows()

'''
平移图片

M=[1 0 tx
   0 1 ty]

'''
'''
flags = -1：imread按解码得到的方式读入图像
flags = 0：imread按单通道的方式读入图像，即灰白图像 
flags = 1：imread按三通道方式读入图像，即彩色图像
'''
img = cv.imread('1.png',0)
rows,cols = img.shape
M = np.float32([[1,0,10],[0,1,20]])
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',img)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

#图像旋转
img = cv.imread('1.png',0)
rows,cols = img.shape
# cols-1 and rows-1 are the coordinate limits.cols-1和row-1是坐标限制
M = cv.getRotationMatrix2D(((cols-1)/2.0,(rows-1)/2.0),90,1)
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',img)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

#仿射变换
'''
在仿射变换中，原始图像中的所有平行线在输出图像中仍将平行。
为了找到变换矩阵，我们需要输入图像中的 三个点 及其在输出图像中的对应位置。
然后cv.getAffineTransform将创建一个2x3矩阵，该矩阵将传递给cv.warpAffine。
'''

img = cv.imread('car.png')
rows,cols,h = img.shape
p1 = np.float32([[50,50],[200,50],[50,200]])
p2 = np.float32([[10,100],[200,50],[100,220]])
M = cv.getAffineTransform(p1,p2)
dst = cv.warpAffine(img,M,(cols,rows))
cv.imshow('img',img)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

#透视变换
'''
对于透视变换，您需要3x3变换矩阵。
即使在转换后，直线也将保持直线。
要找到此变换矩阵，您需要在输入图像上有4个点，在输出图像上需要相应的点。
在这4个点中，其中3个不应共线。
然后可以通过函数cv.getPerspectiveTransform找到转换矩阵。
然后将cv.warpPerspective应用于此3x3转换矩阵。
'''

img = cv.imread('car.png')
rows,cols,ch = img.shape
pts1 = np.float32([[56,65],[220,52],[28,220],[220,220]])
pts2 = np.float32([[0,0],[230,0],[0,230],[230,230]])
M = cv.getPerspectiveTransform(pts1,pts2)
dst = cv.warpPerspective(img,M,(300,300))
cv.imshow('img',img)
cv.imshow('dst',dst)
cv.waitKey(0)
cv.destroyAllWindows()

#图像阈值
#cv.threshold和cv.adaptiveThreshold
#1.简单阈值
'''
如果像素值小于阈值，则将其设置为0，否则将其设置为最大值。
函数cv.threshold用于应用阈值。
第一个参数是源图像，它应该是灰度图像。
第二个自变量是阈值，用于对像素值进行分类。
第三个参数是分配给超过阈值的像素值的最大值。
OpenCV提供了不同类型的阈值，这由函数的第四个参数给出。
通过使用类型cv.THRESH_BINARY完成上述基本阈值处理。所有简单的阈值类型为：
cv.THRESH_BINARY
cv.THRESH_BINARY_INV
cv.THRESH_TRUNC
cv.THRESH_TOZERO
cv.THRESH_TOZERO_INV
该方法返回两个输出。第一个是使用的阈值，第二个输出是阈值图像。
'''
img = cv.imread('1.png',0)
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray',vmin=0,vmax=255)
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

#自适应阈值
'''
该算法基于像素周围的小区域来确定像素的阈值。因此，对于同一图像的不同区域，我们获得了不同的阈值，从而为光照度变化的图像提供了更好的结果。
除了上述参数外，方法cv.adaptiveThreshold还接受三个输入参数：
该adaptiveMethod决定阈值是如何计算的：
cv.ADAPTIVE_THRESH_MEAN_C：该阈值是平均值的附近区域减去恒定的Ç。
cv.ADAPTIVE_THRESH_GAUSSIAN_C：阈值是邻域值减去常数C的高斯加权和。
该BLOCKSIZE确定附近区域的大小和Ç是从邻域像素的平均或加权总和中减去一个常数。
'''

img = cv.imread('1.png',0)
img = cv.medianBlur(img,5)
ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\
            cv.THRESH_BINARY,11,2)
th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()


#Otsu的二值化
'''
在全局阈值化中，我们使用任意选择的值作为阈值。
相比之下，Otsu的方法避免了必须选择一个值并自动确定它的情况。
考虑仅具有两个不同图像值的图像（双峰图像），其中直方图将仅包含两个峰。
一个好的阈值应该在这两个值的中间。
类似地，Otsu的方法从图像直方图中确定最佳全局阈值。
为此，使用了cv.threshold（）函数，其中cv.THRESH_OTSU作为附加标志传递。阈值可以任​​意选择。
然后，算法找到最佳阈值，该阈值作为第一输出返回。
输入图像为噪点图像。
在第一种情况下，将应用值127的全局阈值。
在第二种情况下，将直接应用Otsu的阈值。
在第三种情况下，首先使用5x5高斯核对图像进行滤波以去除噪声，然后应用Otsu阈值处理。
'''
img = cv.imread('noisy2.png',0)
# global thresholding
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv.GaussianBlur(img,(5,5),0)
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
          'Original Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in range(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()